import java.io.Serializable;
import java.util.Random;
import java.util.Vector;


public class AnimalObject implements Serializable {
	//public class AnimalObject implements Runnable {
	//declarations

	public static boolean DEBUG = false;
	public static void setDEBUG(boolean b) {DEBUG = b;}

	protected boolean TYPE = false; 
	//should always be 0 or 1 
	//false = herbivore, true = carnivore
	public boolean getType() {
		return TYPE;
		//false = herbivore
		//true = carnivore
	}
	public void setType(boolean type) {
		this.TYPE = type;
	}
	public boolean queryType() {
		return TYPE;
		//cause i forget
	}

	protected int OFFPOW = -1; //no offensive power bonus
	protected int DEFPOW = -1; //half defensive power bonus
	public void adjustOffPow(int i){
		this.OFFPOW += i;
	}
	public void adjustDefPow(int i){
		this.DEFPOW += i;
	}
	public int getOffPow() {return OFFPOW;}
	public int getDefPow() {return DEFPOW;}

	private int HEALTH = -1;   
	//-1 means something bad happened, should always be >= 0
	private boolean SEX = false;   
	//yes please
	private int MATEABLE = 0; 
	//ED sucks
	private boolean LIVING = false;  
	//THE DEAD SHALL RISE AND FEAST UPON THE LIVING!



	//end declarations


	//setters & gettera
	private int MASS = -1; 
	//-1 means something bad happened, 
	//should always be >= 0
	private int FOODVALUE = -1; 
	private int FOODMAX = -1;
	//-1 means something bad happened, should always be >= 0 
	private int BORROWEDTIME = -1;   
	//-1 means something bad happened
	private int ENERGY = -1;
	//-1 means something bad happened, 
	//should always be >= 0
	//anything over 75 is stored fat
	//living on borrowed time
	public int getBorrowedTime() {
		return BORROWEDTIME;
	}
	public void setBorrowedTime(int time) {
		this.BORROWEDTIME = time;
	}
	public void adjustBorrowedTime(int time) {
		this.BORROWEDTIME += time;
	}

	/////////////////////////////////////////////////////age
	private int AGE = -1;
	//-1 means something bad happened, 
	//should always be >= 0
	private int MAXAGE = 10000;
	///totally arbitrary max age...
	public int getAge() {
		return AGE;
	}
	public void setAge(int age) {
		this.AGE = age;
	}
	public void adjustAge(int age) {
		this.AGE += age;
	}
	public int getMaxAge() {
		return MAXAGE;
	}

	void setMaxAge(int age) {
		this.MAXAGE = age;
	}

	///////////////////////////////////////////////////////health
	public int getHealth() {
		return HEALTH;
	}
	public void setHealth(int health) {
		this.HEALTH = health;
	}
	public void adjustHealth(int health){
		this.HEALTH += health;
	}

	//mass
	public int getMass() {
		return MASS;
	} 
	public void setMass(int mass) {
		this.MASS = mass;
	}
	public void adjustMass(int change) {
		this.MASS += change;
	}

	//we know our location
	private loc LOCATION;
	//pull this by querying the location object
	//x,y should never be out of bounds for our env size
	//the number of 'squares' you can move in a turn
	private int VELOCITY = -1;   
	//-1 means something bad happened, should always be >= 0
	//probably will be 1, maybe 2 for walking
	//3-6 is running at some random speed
	//anything beyond that is... fast
	private int MAXVELOCITY = -1;    
	//-1 means something bad happened, should always be >= 0
	//should not go higher than 10
	//10 is super fast, only the fastest will go like greased lightning
	protected int AREA = 30 ;
	public void adjustArea(int i) {
		this.AREA += i;
	}
	public int getArea() {
		return AREA;
	}
	//area is the maximum area the animal can see/sense
	//bas is 10, low is 5, high is 15
	//carnivores should default to 10 at a min
	//herbivores will have 10 at a max
	//0 is blind, scent/sound hunters of the world rejoice!
	/////////////////////////////////////////location

	public void instanceLocation() {
		this.LOCATION = new loc(-1,-1);
	}

	public void setLocation(int x, int y) {
		this.LOCATION.setLoc(x,y);
		//testing = System.out.println("setLocation"+x+","+y);
	}
	public void setLocation(loc l){
		this.LOCATION = l;
	}
	public loc getLocation() {
		return LOCATION;
	}


	//mateable
	public int getMateable() {
		return MATEABLE;
	}
	public void setMateable(int t) {
		this.MATEABLE = t;
	}

	//living
	public boolean getLiving() {
		return LIVING;
	}
	public void setLiving(boolean life) {
		this.LIVING = life;
	}

	//velocity
	public void setVelocity(int velocity) {
		this.VELOCITY = velocity;
	}
	public int getVelocity() {
		return VELOCITY;
	}
	public void setMaxVelocity(int velocity) {
		this.MAXVELOCITY = velocity;
	}
	public int getMaxVelocity() {
		return MAXVELOCITY;
	}


	///////////////////////////////////////////////////////food value
	public int getFoodValue() {
		return this.FOODVALUE;
	}
	public int getFoodMax() {
		return this.FOODMAX;
	}
	public void setFoodMax(int n) {
		this.FOODMAX = n;
	}
	public void setFoodValue(int foodvalue) {
		this.FOODVALUE = foodvalue;
	}
	//food value adjustment
	public void adjustFoodValue(int adjust) { //increment or decrement
		this.FOODVALUE += adjust;
	}

	////////////////////////////////////////energy
	public void setEnergy(int energy) {
		//probably wont use this but its here in case
		this.ENERGY = energy;
	}
	public int getEnergy() {
		return ENERGY;
	}
	//this is adjusted by current velocity
	//this is also adjusted by time (-1)
	//eating is +whatever, eating is the only way to gain energy
	public void adjustEnergy(int energy){
		this.ENERGY += energy;
	} 

	//sexing the animal
	public boolean getSex() {
		return SEX;
	}
	public void setSex(boolean b) {
		//int 0 female, else male
		this.SEX = b;
	}
	//food value calculator
	public void calculateFoodValue() {
		//magic calc for food value
		//may call set or adjust
		//arbitrarily foodvalue = energy + half mass;
		//we will do this once on death, then decrement till 0 or so.
		this.FOODVALUE = (this.getEnergy() + this.getMass()/2); 
	}
	//fleeing. animal will burn energy faster in this state
	//targets searching et al
	private boolean FLEEING = false;  //is the animal running away terrified 
	private boolean CHASING = false;  //is the animal chasing prey 
	private boolean SEARCHING = false; //are we looking (universal) 
	private AnimalObject FOCUS = null;
	//focus is either the animal doing the chasing
	//or the animal being chased, respectively depending on role
	//alternatively its the animal being mated with
	//or being mated by respectively
	public boolean getFleeing() {
		return FLEEING;
	}
	public void setFleeing(boolean runaway) {
		this.FLEEING = runaway;
	}
	//chasing, animal will burn energy faster in this state
	public boolean getChasing() {
		return CHASING;
	}
	public void setChasing(boolean a) {
		this.CHASING = a;
	}
	//searching
	public boolean getSearching() {
		return SEARCHING;
	}
	public void setSearching(boolean search){
		this.SEARCHING = search;
	}
	public void setFocus(AnimalObject a){
		this.FOCUS = a;
	}
	public AnimalObject getFocus() {
		return this.FOCUS;
	}

	//setting family vars
	//how big is our herd/pack/etc
	public int getFamily() {
		return FAMILY;
	}
	public void setFamily(int i) {
		this.FAMILY = i;
	}

	//who is in our herd/pack/etc

	private Vector<AnimalObject> FAMILYOBS; 
	//vector of animals in family
	private Vector<AnimalObject> DEADFAMILYOBJS;

	private int FAMILY;// = this.getFamilyObjects().size(); 
	//-1 means something bad happened, 
	//should always be >= 0
	//should be number of things in vector
	public int MAXFAMILY = -1;       
	//-1 means no max, carnivore should always be >= 0

	private AnimalObject MOTHER;
	//mother object, matriarchy
	private AnimalObject FATHER;
	//WHO IS YOUR DADDY AND WHAT DOES HE DO?
	@SuppressWarnings("unused")
	private boolean DOMINANT = false;
	//am i the leader of the herd/pack/etc
	public AnimalObject getMother() {
		return MOTHER;
	}
	public AnimalObject getFather() {
		return FATHER;
	}
	public void setMother(AnimalObject mom) {
		this.MOTHER = mom;
	}
	public void setFather(AnimalObject dad){
		this.FATHER = dad;
	}

	public Vector<AnimalObject> getFamilyObjects() {
		return this.FAMILYOBS;
	}
	public Vector<AnimalObject> getDeadFamilyObject() {
		return this.DEADFAMILYOBJS;
	}
	public void addDeadFamilyObject(AnimalObject a) {
		if(this.LIVING == true) //new animal
			this.DEADFAMILYOBJS.add(a);
	}
	//drop another animal on the vector
	public void addFamilyObject(AnimalObject a) {
		if(this.LIVING == true) //new animal
			this.FAMILYOBS.add(a);
	}




	//calculators for various things not grouped above for some reason
	//that probably makes sense only to me
	//spend/get energy
	protected boolean EATING = false;
	public void setEating(boolean b) {EATING = b;}
	public boolean getEatig() {return EATING;}

	//initialization
	public AnimalObject() {
		//this.LOCATION = new loc();
	} //constructor, does nothing, solves errors


	/* both */
	//animals area and proximity
	private Vector<loc> myArea;
	public void getMyAreaProximity() {
		myArea = AreaProximityHandler.getLocationAreas(this, this.getArea());
		// deprecated myProx = AreaProximityHandler.getLocationProximities(this);
	}
	public Vector<loc> getMyAreaLocs() {
		return myArea;
	}

	private int DISPOSITION;
	public int getDisposition(){
		return DISPOSITION;
	}
	public void setDisposition(int d) {
		this.DISPOSITION = d;
	}



	public void FindMate() { 
		//invoke mate handler
		MateHandler.findPotentials(this);

		//System.out.println("enter mate handler"); //test
	}
	public void MoveAnimal() {
		//invoke move handler
		//this is a hack for testing purposes, fix later
		//this.setFleeing(true); // why not
		Random R = new Random();
		MoveHandler.doMove(this.myArea.get(R.nextInt(this.myArea.size())),this);
	}
	public void splitMe() {
		//invoke the budding handler
		BirthHandler.budding(this);
	}
	public void EatThings() {
		if(this.getFleeing() == true) { 
			this.MoveAnimal();
			this.setDisposition(0);
		}
		if(this.getDisposition() == 2) 
			EatHandler.findFood(this);


	}

	//SimConstants.pauseButton == false, pause thread.

	private boolean MIGRATE = false;
	public void setMigrate(boolean t) {
		this.MIGRATE = t;
	}
	public boolean getMigrate() {
		return MIGRATE;
	}


	public void decisionTree() {
		Random R = new Random();
		
		if(this.getMateable() > 0 )
			--MATEABLE;
		if(this.getLiving() == true) 
			DeathHandler.killChecksOnAnimal(this); //call this every cycle
		
		//so... if we escaped death...
		if(this.getLiving() == true) {
			myArea=AreaProximityHandler.getLocationAreas(this, this.getArea());
			this.adjustEnergy(-1); //living takes energy
			

			//System.out.println(this.getEnergy()); //test

			if(this.getSex()) {
				this.setDisposition(1);
				//if male, go find some strange
				//if(R.nextBoolean())
					//this.setDisposition(2);
					//half the time, just go eat, its less of a hassle
			}
			 
			if(this.getEnergy() < 55) {
				this.setDisposition(2);
			}

			if(this.getFleeing() || this.MIGRATE)
				this.setDisposition(0);		
			
			if(this.getChasing())
				this.setDisposition(4);
			
			
			if(this.getMass() > 100) {
				this.setDisposition(3);
			}
			
			switch(this.getDisposition()) {
			case 0: //move & migrat
				if(EATING) //we dont want to move while eating
					break;
				this.MoveAnimal();
				if(DEBUG)
					System.out.println("move move");
				break;
			case 1: //PLOW THE FIELDS!
				if(DEBUG)
					System.out.println("WE WANTS THE POON!");
				this.FindMate();
				break;
			case 2: //eat
				if(DEBUG)
					System.out.println("nom nom nom");
				this.EatThings();
				break;
			case 3: //fragmentation
				//we got too big, we need to fragment
				if(DEBUG)
					System.out.println("WonderTwins!");
				this.splitMe();
				break;
			case 4: //get me some food
				if(DEBUG)
					System.out.println("cry havok and let slip the hogs of war");
					//its an Archer quote
				if(this.getChasing()) {
					MoveHandler.doMove(this.getFocus().getLocation(), this);
				}
					break;
			default: // do nothing
				this.MoveAnimal();
				break;

			}

		} 
	}


}
